/**
 * fluent-ffmpeg 使用示例
 * 这个文件展示了fluent-ffmpeg的主要功能和参数设置方法
 */

// 引入所需模块
const ffmpeg = require('fluent-ffmpeg');
const path = require('path');
const fs = require('fs');

// 输入输出路径设置
const inputPath = 'input3.mp4';
const outputPath = 'output';

// =====================================================
// 1. 基本转换示例
// =====================================================

function basicConversion() {
  console.log('开始基本转换示例...');
  
  ffmpeg(inputPath)
    // 设置视频编解码器
    .videoCodec('libx264')
    
    // 设置音频编解码器
    .audioCodec('aac')
    
    // 设置视频比特率 (kb/s)
    .videoBitrate(1000)
    
    // 设置音频比特率 (kb/s)
    .audioBitrate(128)
    
    // 设置输出格式
    .format('mp4')
    
    // 设置视频帧率
    .fps(30)
    
    // 设置视频尺寸
    .size('1280x720')
    
    // 设置音频声道数
    .audioChannels(2)
    
    // 设置音频采样率
    .audioFrequency(44100)
    
    // 进度回调
    .on('progress', (progress) => {
      console.log(`处理进度: ${Math.floor(progress.percent)}% 完成`);
      console.log(`处理速度: ${progress.currentFps} fps`);
      console.log(`当前时间点: ${progress.timemark}`);
    })
    
    // 完成回调
    .on('end', () => {
      console.log('基本转换完成!');
    })
    
    // 错误回调
    .on('error', (err) => {
      console.error('转换出错: ', err);
    })
    
    // 开始回调 (命令执行时)
    .on('start', (commandLine) => {
      console.log('FFmpeg 命令: ' + commandLine);
    })
    
    // 保存到文件
    .save(path.join(outputPath, 'basic_output.mp4'));
}

// =====================================================
// 2. HLS (HTTP Live Streaming) 转换
// =====================================================

function convertToHLS() {
  // console.log('开始HLS转换示例...');
  
  // 确保输出目录存在
  const outputDir = path.join(outputPath, 'hls2');
  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }
  
  // // 检查输入文件是否存在
  // if (!fs.existsSync(inputPath)) {
  //   console.error(`输入文件不存在: ${inputPath}`);
  //   return;
  // }
  
  ffmpeg(inputPath)
    .videoCodec('libx264')
    .audioCodec('aac')
    .outputOptions([
      '-hls_time', '10',
      '-hls_list_size', '0',
      '-hls_segment_filename', path.join(outputDir, 'segment%03d.ts'),
      '-f', 'hls'
    ])
    .output(path.join(outputDir, 'playlist.m3u8'))
    .on('start', commandLine => {
      console.log('FFmpeg命令:', commandLine);
    })
    .on('progress', progress => {
      if (progress.percent) {
        console.log(`转换进度: ${Math.round(progress.percent)}%`);
      }
    })
    .on('stderr', stderrLine => {
      console.log('FFmpeg输出:', stderrLine);
    })
    .on('end', () => {
      console.log('HLS 转换完成!');
    })
    .on('error', (err, stdout, stderr) => {
      console.error('转换失败:', err.message);
      console.error('FFmpeg stdout:', stdout);
      console.error('FFmpeg stderr:', stderr);
    })
    .run();
}
// convertToHLS()

// =====================================================
// 3. 多码率 HLS 转换 (自适应比特率)
// =====================================================
convertToAdaptiveHLS();
function convertToAdaptiveHLS() {
  console.log('开始多码率HLS转换示例...');
  
  // 确保输出目录存在
  const outputDir = path.join(outputPath, 'adaptive_hls3');
  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }
  
  // 检查输入文件是否存在
  if (!fs.existsSync(inputPath)) {
    console.error(`输入文件不存在: ${inputPath}`);
    return;
  }
  
  // 创建流目录
  for (let i = 0; i < 3; i++) {
    const streamDir = path.join(outputDir, `stream_${i}`);
    if (!fs.existsSync(streamDir)) {
      fs.mkdirSync(streamDir, { recursive: true });
    }
  }
  
  ffmpeg(inputPath)
    .videoCodec('libx264')
    .audioCodec('aac')
    
    // 多码率 HLS 的复杂选项
    .outputOptions([
      // 创建三个不同质量的视频流和音频流
      '-map 0:v:0', '-map 0:a:0', '-map 0:v:0', '-map 0:a:0', '-map 0:v:0', '-map 0:a:0',
      
      // 第一个质量 (高) - 720p, 2000kbps
      '-b:v:0 2000k', '-c:v:0 libx264', '-s:v:0 1280x720', '-profile:v:0 main',
      
      // 第二个质量 (中) - 480p, 1000kbps
      '-b:v:1 1000k', '-c:v:1 libx264', '-s:v:1 854x480', '-profile:v:1 main',
      
      // 第三个质量 (低) - 360p, 500kbps
      '-b:v:2 500k', '-c:v:2 libx264', '-s:v:2 640x360', '-profile:v:2 baseline',
      
      // 所有流的音频设置
      '-c:a aac', '-b:a 128k', '-ac 2',
      
      // 映射流
      '-var_stream_map', 'v:0,a:0 v:1,a:1 v:2,a:2',
      
      // 主播放列表名称
      '-master_pl_name master.m3u8',
      
      // HLS 设置
      '-f hls',
      '-hls_time 30',        // 每个分段的时长
      '-hls_list_size 0',   // 保留所有分段
      '-hls_segment_type mpegts',   // 使用 MPEG-TS 容器格式
      '-hls_flags independent_segments', // 生成独立的分段
      
      // 关键: 我们不需要创建子目录，因为FFmpeg不会在m3u8中添加路径前缀
      // 直接将分段文件输出到对应的目录
      '-hls_segment_filename', path.join(outputDir, 'stream_%v/data%03d.ts')
    ])
    
    // 输出文件 (%v 将被替换为视频流索引)
    .output(path.join(outputDir, 'stream_%v/playlist.m3u8'))
    
    .on('start', commandLine => {
      console.log('FFmpeg命令:', commandLine);
    })
    
    .on('progress', progress => {
      if (progress.percent) {
        console.log(`处理进度: ${Math.round(progress.percent)}% 完成`);
      }
    })
    
    .on('stderr', stderrLine => {
      console.log('FFmpeg输出:', stderrLine);
    })
    
    .on('end', () => {
      console.log('多码率 HLS 转换完成!');
      
      // 创建主播放列表，确保所有路径正确
      try {
        const masterPlaylistPath = path.join(outputDir, 'master.m3u8');
        console.log(`创建主播放列表: ${masterPlaylistPath}`);
        
        // 创建一个简单的主播放列表
        const masterContent = `#EXTM3U
#EXT-X-VERSION:3
        
#EXT-X-STREAM-INF:BANDWIDTH=2128000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2"
stream_0/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1128000,RESOLUTION=854x480,CODECS="avc1.4d401f,mp4a.40.2"
stream_1/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=628000,RESOLUTION=640x360,CODECS="avc1.42c00d,mp4a.40.2"
stream_2/playlist.m3u8
`;
        
        // 写入主播放列表文件
        fs.writeFileSync(masterPlaylistPath, masterContent);
        console.log('主播放列表已创建');
      } catch (error) {
        console.error('创建主播放列表时出错:', error);
      }
    })
    
    .on('error', (err, stdout, stderr) => {
      console.error('转换失败:', err.message);
      console.error('FFmpeg stdout:', stdout);
      console.error('FFmpeg stderr:', stderr);
    })
    
    .run();
}

// =====================================================
// 4. 视频剪切
// =====================================================

function trimVideo() {
  console.log('开始视频剪切示例...');
  
  ffmpeg(inputPath)
    // 设置开始时间 (从第30秒开始)
    .seekInput('00:00:30')
    
    // 设置持续时间 (剪切20秒)
    .duration('20')
    
    // 或者可以这样设置结束时间
    // .seekInput(30).duration(20)
    // .seekInput(30).to('00:00:50')
    
    .on('end', () => {
      console.log('视频剪切完成!');
    })
    
    .on('error', (err) => {
      console.error('剪切出错: ', err);
    })
    
    .save(path.join(outputPath, 'trimmed_output.mp4'));
}

// =====================================================
// 5. 提取音频
// =====================================================

function extractAudio() {
  console.log('开始音频提取示例...');
  
  ffmpeg(inputPath)
    // 禁用视频
    .noVideo()
    
    // 设置音频编解码器
    .audioCodec('libmp3lame')
    
    // 设置音频质量
    .audioBitrate(192)
    
    .on('end', () => {
      console.log('音频提取完成!');
    })
    
    .on('error', (err) => {
      console.error('提取出错: ', err);
    })
    
    .save(path.join(outputPath, 'audio_only.mp3'));
}

// =====================================================
// 6. 添加水印
// =====================================================

function addWatermark() {
  console.log('开始添加水印示例...');
  
  ffmpeg(inputPath)
    // 使用复杂滤镜添加水印
    .videoFilters({
      filter: 'overlay',
      options: {
        x: '10',            // 水印的X坐标
        y: 'main_h-overlay_h-10'  // 水印位于视频底部，上方留出10像素
      },
      inputs: ['main', 'watermark.png']  // 输入为主视频和水印图片
    })
    
    .on('end', () => {
      console.log('水印添加完成!');
    })
    
    .on('error', (err) => {
      console.error('添加水印出错: ', err);
    })
    
    .save(path.join(outputPath, 'watermarked_video.mp4'));
}

// =====================================================
// 7. 截图
// =====================================================

function takeScreenshots() {
  console.log('开始视频截图示例...');
  
  ffmpeg(inputPath)
    .screenshots({
      // 截图数量
      count: 5,
      // 截图文件夹
      folder: path.join(outputPath, 'screenshots'),
      // 截图尺寸
      size: '640x360',
      // 文件名格式: 包含时间戳和索引
      filename: 'thumbnail-at-%s-seconds-%i.png',
      // 可以使用具体时间点代替count
      // timestamps: ['00:01:00', '00:02:00', '00:05:00', '50%', '01:10:00']
    })
    
    .on('filenames', (filenames) => {
      console.log('即将生成的截图文件: ' + filenames.join(', '));
    })
    
    .on('end', () => {
      console.log('截图完成!');
    })
    
    .on('error', (err) => {
      console.error('截图出错: ', err);
    });
}

// =====================================================
// 8. 合并视频
// =====================================================

function mergeVideos() {
  console.log('开始视频合并示例...');
  
  // 确保目录存在
  const tempDir = path.join(outputPath, 'temp');
  if (!fs.existsSync(tempDir)) {
    fs.mkdirSync(tempDir, { recursive: true });
  }
  
  ffmpeg()
    // 添加多个输入文件
    .input('part1.mp4')
    .input('part2.mp4')
    .input('part3.mp4')
    
    // 也可以使用 mergeToFile 方法
    .mergeToFile(path.join(outputPath, 'merged_output.mp4'), tempDir)
    
    .on('progress', (progress) => {
      console.log(`处理进度: ${Math.floor(progress.percent)}% 完成`);
    })
    
    .on('end', () => {
      console.log('视频合并完成!');
      
      // 清理临时文件
      // fs.rmdirSync(tempDir, { recursive: true });
    })
    
    .on('error', (err) => {
      console.error('合并出错: ', err);
    });
}

// =====================================================
// 9. 视频压缩
// =====================================================

function compressVideo() {
  console.log('开始视频压缩示例...');
  
  ffmpeg(inputPath)
    .videoCodec('libx264')
    .audioCodec('aac')
    
    // CRF 方法，值范围 0-51，18-28是合理范围，值越低质量越高
    .outputOptions('-crf 23')
    
    // 使用预设加快编码速度 (ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow)
    .outputOptions('-preset fast')
    
    // 调整调谐参数，用于具体类型的视频 (film,animation,grain...)
    .outputOptions('-tune film')
    
    .on('progress', (progress) => {
      console.log(`处理进度: ${Math.floor(progress.percent)}% 完成`);
    })
    
    .on('end', () => {
      console.log('视频压缩完成!');
    })
    
    .on('error', (err) => {
      console.error('压缩出错: ', err);
    })
    
    .save(path.join(outputPath, 'compressed_video.mp4'));
}

// =====================================================
// 10. 为 DASH 格式转换视频
// =====================================================

function convertToDASH() {
  console.log('开始DASH转换示例...');
  
  ffmpeg(inputPath)
    .videoCodec('libx264')
    .audioCodec('aac')
    .outputOptions([
      // 多码率设置
      '-map 0:v:0', '-map 0:a:0', '-map 0:v:0', '-map 0:a:0',
      
      // 第一个质量
      '-b:v:0 2000k', '-s:v:0 1280x720',
      
      // 第二个质量
      '-b:v:1 1000k', '-s:v:1 854x480',
      
      // 音频设置
      '-c:a aac', '-b:a 192k',
      
      // DASH 特定选项
      '-use_timeline 1',
      '-use_template 1',
      '-window_size 5',
      '-adaptation_sets "id=0,streams=v id=1,streams=a"',
      '-f dash'
    ])
    
    .output(path.join(outputPath, 'dash/manifest.mpd'))
    
    .on('progress', (progress) => {
      console.log(`处理进度: ${Math.floor(progress.percent)}% 完成`);
    })
    
    .on('end', () => {
      console.log('DASH 转换完成!');
    })
    
    .on('error', (err) => {
      console.error('转换出错: ', err);
    })
    
    .run();
}

// =====================================================
// 11. 获取视频元数据
// =====================================================

function getVideoMetadata() {
  console.log('开始获取视频元数据...');
  
  ffmpeg.ffprobe(inputPath, (err, metadata) => {
    if (err) {
      console.error('获取元数据出错: ', err);
      return;
    }
    
    console.log('视频元数据:');
    console.log('---------------------');
    
    // 文件信息
    const format = metadata.format;
    console.log(`文件名: ${format.filename}`);
    console.log(`时长: ${format.duration} 秒`);
    console.log(`比特率: ${format.bit_rate} bit/s`);
    console.log(`文件大小: ${format.size} 字节`);
    
    // 视频流信息
    const videoStream = metadata.streams.find(s => s.codec_type === 'video');
    if (videoStream) {
      console.log('\n视频流信息:');
      console.log(`编解码器: ${videoStream.codec_name}`);
      console.log(`分辨率: ${videoStream.width}x${videoStream.height}`);
      console.log(`帧率: ${videoStream.r_frame_rate}`);
      console.log(`像素格式: ${videoStream.pix_fmt}`);
    }
    
    // 音频流信息
    const audioStream = metadata.streams.find(s => s.codec_type === 'audio');
    if (audioStream) {
      console.log('\n音频流信息:');
      console.log(`编解码器: ${audioStream.codec_name}`);
      console.log(`声道数: ${audioStream.channels}`);
      console.log(`采样率: ${audioStream.sample_rate}`);
      console.log(`比特率: ${audioStream.bit_rate}`);
    }
    
    console.log('---------------------');
    console.log('元数据获取完成!');
  });
}

// =====================================================
// 12. 创建视频缩略图网格
// =====================================================

function createThumbnailGrid() {
  console.log('开始创建缩略图网格...');
  
  ffmpeg(inputPath)
    // 创建3x3的缩略图网格
    .outputOptions([
      // 每10秒截取一帧
      '-vf select=\'not(mod(n\\,300))\',scale=320:180,tile=3x3'
    ])
    .frames(1)
    .on('end', () => {
      console.log('缩略图网格创建完成!');
    })
    .on('error', (err) => {
      console.error('创建缩略图网格出错: ', err);
    })
    .save(path.join(outputPath, 'thumbnail_grid.jpg'));
}

// =====================================================
// 13. 视频旋转与翻转
// =====================================================

function rotateVideo() {
  console.log('开始视频旋转示例...');
  
  ffmpeg(inputPath)
    // 顺时针旋转90度
    .videoFilters('transpose=1')
    
    // 其他旋转选项:
    // transpose=0: 逆时针旋转90度并垂直翻转
    // transpose=1: 顺时针旋转90度
    // transpose=2: 逆时针旋转90度
    // transpose=3: 顺时针旋转90度并垂直翻转
    
    // 也可以水平翻转或垂直翻转:
    // .videoFilters('hflip') // 水平翻转
    // .videoFilters('vflip') // 垂直翻转
    
    .on('end', () => {
      console.log('视频旋转完成!');
    })
    .on('error', (err) => {
      console.error('旋转出错: ', err);
    })
    .save(path.join(outputPath, 'rotated_video.mp4'));
}

// =====================================================
// 14. 调整视频速度
// =====================================================

function changeVideoSpeed() {
  console.log('开始调整视频速度示例...');
  
  ffmpeg(inputPath)
    // 通过setpts调整视频速度 (0.5x表示加快2倍)
    .videoFilters('setpts=0.5*PTS')
    
    // 通过atempo调整音频速度 (2.0表示加快2倍，范围0.5-2.0)
    .audioFilters('atempo=2.0')
    
    // 对于更极端的音频速度调整，需要级联多个atempo
    // .audioFilters('atempo=2.0,atempo=2.0') // 4倍速
    
    .on('end', () => {
      console.log('视频速度调整完成!');
    })
    .on('error', (err) => {
      console.error('速度调整出错: ', err);
    })
    .save(path.join(outputPath, 'faster_video.mp4'));
}

// =====================================================
// 15. 添加字幕
// =====================================================

function addSubtitles() {
  console.log('开始添加字幕示例...');
  
  ffmpeg(inputPath)
    // 添加字幕文件，会烧录到视频中
    .videoFilters(`subtitles=subtitles.srt`)
    
    // 可以自定义字幕样式
    // .videoFilters('subtitles=subtitles.srt:force_style=\'FontName=Arial,FontSize=24,PrimaryColour=&H00FFFFFF\'')
    
    .on('end', () => {
      console.log('添加字幕完成!');
    })
    .on('error', (err) => {
      console.error('添加字幕出错: ', err);
    })
    .save(path.join(outputPath, 'video_with_subtitles.mp4'));
}

// =====================================================
// 主函数 - 按需调用以上功能
// =====================================================

// 确保输出目录存在
if (!fs.existsSync(outputPath)) {
  fs.mkdirSync(outputPath, { recursive: true });
}

// 执行转换示例 (取消注释你需要的功能)
// basicConversion();
// convertToHLS();
// convertToAdaptiveHLS();
// trimVideo();
// extractAudio();
// addWatermark();
// takeScreenshots();
// mergeVideos();
// compressVideo();
// convertToDASH();
// getVideoMetadata();
// createThumbnailGrid();
// rotateVideo();
// changeVideoSpeed();
// addSubtitles();

// 默认执行基本转换
// basicConversion();

// console.log('请在上面的示例函数中取消注释，以执行您需要的功能。');
// console.log('更多信息请参考 fluent-ffmpeg 文档: https://github.com/fluent-ffmpeg/node-fluent-ffmpeg'); 